#include "./superSnake.h"

Map map[MAX_MAP][MAX_MAP];					// 地图
Coord head_coo[2];							// 蛇头坐标
Map head_dir = RIGHT;						// 蛇头前进方向
bool go_straight = false;
bool eat_bean = false;
Coord straight_num = 0;
Coord eat_bean_num = 0;
bool is_go_wall = false;
bool is_body_turn = false;					// 因为遇到身体而转向
bool is_body_ago = false;					// 避免死路再走几步
Coord grade, old_grade;						// 分数与前分数
bool isBean = false;						// 场上是否有得分豆
Coord bean_coo[2];							// 存放得分豆坐标
Map bean_wall = SKY;
bool wallIsRow = false;

int main() {
	srand((unsigned int)time(NULL));
	//	gameOpen();
	test();
	return 0;
}

void test(){
	initSnake();
	showMap();
	while(!gameOver()){
//		if(grade == 50){
//			printf("VICTORY!!!");
//			break;
//		}
		eat_bean = moveSnake();
		
		system(CLEAR_SCREEN);
		showMap();
		moveSSS();
		usleep(1000);
	}	
}


// 开始游戏
void gameOpen() {
	initSnake();
	while (1) {
		showMap();
		if (gameOver()) {
			break;
		}
		moveSnake();
		system(CLEAR_SCREEN);
	}
	printf("\tGAME OVER!\n");
}


// 游戏结束判断
bool gameOver() {
	if (head_coo[0] < 0 || head_coo[0] >= MAX_MAP || head_coo[1] < 0 || head_coo[1] >= MAX_MAP) {
		return true;
	}
	if (grade < old_grade) {
		return true;
	}
	return false;
}


// 生成随机坐标
Coord randCoord(bool isX) {
	if (isX) {
		Coord factor1 = rand() % 5,
		factor2 = rand() % 2;
		if (factor1 == 0) {
			return rand() % 15;
		} else {
			if (factor2 == 0) {
				return ((rand() % 15) + factor1) % 15;
			} else {
				return ((rand() % 15) - factor1 + 15) % 15;
			}
		}
	}
	return rand() % 15;
}


// 获取转向算法
Map getTurnDir(Map main_dir, Map turn){
	if(turn == LEFT){
		return (main_dir + 1)% 4;
	} else if(turn == RIGHT){
		return (main_dir + 3)% 4;
	} else if(turn == DOWN){
		return (main_dir + 2)% 4;
	}
}


// 根据方向获取下一步坐标
void turnToCoord(Coord *x, Coord *y, Map dir){
	switch (dir) {
	case UP:
		(*x)--;
		break;
	case LEFT:
		(*y)--;
		break;
	case DOWN:
		(*x)++;
		break;
	case RIGHT:
		(*y)++;
		break;
		default:
			//TODO
			break;
	}
}


bool isWall(Coord x, Coord y){
	if(x < 0 || x >= MAX_MAP || y < 0 || y >= MAX_MAP){
		return true;
	}
	return false;
}


bool isBody(Coord x, Coord y){
	if(map[x][y] >= UP && map[x][y] <= RIGHT){
		return true;
	}
	return false;
}


// 初始化蛇
void initSnake() {
	for (Coord i = 0; i < MAX_MAP; i++) {  
		for (Coord j = 0; j < MAX_MAP; j++) {  
			map[i][j] = SKY;  
		}  
	}
	
	// 设蛇头坐标为(0, 3)，并更新地图
	head_coo[0] = 0;
	head_coo[1] = 3;
	map[0][3] = RIGHT;
	
	for (Coord i = 2; i > 0; i--) {
		// 设蛇身坐标为(3, i)，并更新地图
		map[0][i] = RIGHT;
	}
	map[0][0] = UP;
	
	
	grade = old_grade = 3;
	
	createBean();
}


// 移动蛇身体
void moveBody(Coord dad_x, Coord dad_y) {
	Coord now_x = dad_x, now_y = dad_y;
	Map now_dir = getTurnDir(map[dad_x][dad_y], DOWN);
	turnToCoord(&now_x, &now_y, now_dir);
	
	if(!isWall(now_x, now_y)){
		if(isBody(now_x, now_y)){
			if(now_x == head_coo[0] && now_y == head_coo[1]){
				map[dad_x][dad_y] = SKY;
				return; 
			}
			moveBody(now_x, now_y);
			return;
		}
	}
	
	// 将尾巴设置为SKY，代表前进一步
	map[dad_x][dad_y] = SKY;
	return;
}

// 移动蛇头
bool moveSnake() {
	Coord old_x = head_coo[0], old_y = head_coo[1];
	Coord now_x = old_x, now_y = old_y;
	Coord old_dir = map[old_x][old_y];
	// 根据行进方向获取下一步坐标
	turnToCoord(&now_x, &now_y, head_dir);
	
	
	// 目标坐标为得分豆 
	if(map[now_x][now_y] == BEAN){
		isBean = false;
		map[now_x][now_y] = head_dir;
		
		// 更新蛇头坐标
		head_coo[0] = now_x;
		head_coo[1] = now_y;
		createBean();
		return true;
	}
	
	// 目标坐标非得分豆
	map[old_x][old_y] = old_dir;
	moveBody(old_x, old_y);
	
	// 更新蛇头坐标
	map[now_x][now_y] = head_dir;
	head_coo[0] = now_x;
	head_coo[1] = now_y;
	return false;
}


// 随机生成得分豆
void createBean() {
	if (!isBean) {
		Coord bean_x = 0, bean_y = 0;
		while(1){
			bean_x = randCoord(true);
			bean_y = randCoord(false);
			
			Coord factor[2] = {2, -2};
			bool isOK = true;
			for(int i = 0; i < 2; i++){
				if(isWall(bean_x + factor[i], bean_y)){
					continue;
				}
				if(isBody(bean_x + factor[i], bean_y)){
					isOK = false;
					break;
				}
			}
			for(int i = 0; i < 2; i++){
				if(isWall(bean_x, bean_y + factor[i])){
					continue;
				}
				if(isBody(bean_x, bean_y + factor[i])){
					isOK = false;
					break;
				}
			}
			
			if(isOK && map[bean_x][bean_y] == SKY){
				break;
			}
		}
		bean_coo[0] = bean_x;
		bean_coo[1] = bean_y;
		map[bean_x][bean_y] = BEAN;
		isBean = true;
		getBeanWall();
	}
}


// 映射地图
void showMap() {
	old_grade = grade;
	grade = 0;
	for (Coord x = -1; x <= MAX_MAP; x++) {
		for (Coord y = -1; y <= MAX_MAP; y++) {
			if (y == MAX_MAP) {
				printf("##\n");
			} else if (x == -1 || x == MAX_MAP || y == -1) {
				printf("##");
			} else {
				switch (map[x][y]) {
					case SKY: // 天空
					printf("  ");
					break;
					case BEAN: // 豆子
					printBean();
					break;
					default:
						grade++;
						printSnake(x, y);
						break;
				}
			}
		}
	}
	printf("grade:%d\n", grade);
}


// 打印蛇
void printSnake(int x, int y) {
	// 将字体颜色改为蓝色
#ifdef _WIN32
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hConsole, Color[1]);
#else
	printf("%s", Color[1]);
#endif
	
	// 获取方向
	Map dir = map[x][y];
	
	// 打印身体
	switch (dir) {
	case UP:
		printf("↑");
		break;
	case DOWN:
		printf("↓");
		break;
	case LEFT:
		printf("←");
		break;
	case RIGHT:
		printf("→");
		break;
		default:
			break;
	}
#ifndef _WIN32
	printf(" ");
#endif
	
	// 将字体颜色改为白色
#ifdef _WIN32
	SetConsoleTextAttribute(hConsole, Color[2]);
#else
	printf("%s", Color[2]);
#endif
}


// 打印得分豆
void printBean() {
	// 将字体颜色改为黄色
#ifdef _WIN32
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hConsole, Color[0]);
#else
	printf("%s", Color[0]);
#endif
	
	// 打印豆子
	printf("<>");
	
	// 将字体颜色改为白色
#ifdef _WIN32
	SetConsoleTextAttribute(hConsole, Color[2]);
#else
	printf("%s", Color[2]);
#endif
}


// 4.0

// 蛇的下步走向
void getNextDir(){
	Map next_dir = getTurnDir(head_dir, LEFT);
	for(int i = 0;i < 3; i++){
		Coord x = head_coo[0], y = head_coo[1];
		turnToCoord(&x, &y, next_dir);
		if(isWall(x, y) || isBody(x, y)){
			next_dir = getTurnDir(next_dir, RIGHT);
			continue;
		} else {
			head_dir = next_dir;
			return;
		}
	}
}


// 获取豆最靠近的墙
void getBeanWall(){
	Coord north = bean_coo[0],
		  west = bean_coo[1],
		  other = north + west;
	if(other >= 14){
		if(north >= west){
			if(west == 1 && north == 13) {
				bean_wall = LEFT;
				wallIsRow = true;
			} else {
				bean_wall = DOWN;
				wallIsRow = false;
			}
		} else{
			bean_wall = RIGHT;
			wallIsRow = true;
		}
	} else {
		if(north <= west){
			bean_wall = UP;
			wallIsRow = false;
		} else {
			bean_wall = LEFT;
			wallIsRow = true;
		}
	}
}

bool okGoeat(){
	switch (bean_wall) {
	case UP:
		if(bean_coo[0] > head_coo[0] && bean_coo[1] == head_coo[1]){
			return true;
		}
		break;
	case LEFT:
		if(bean_coo[0] == head_coo[0] && bean_coo[1] > head_coo[1]){
			return true;
		}
		break;
	case DOWN:
		if(bean_coo[0] < head_coo[0] && bean_coo[1] == head_coo[1]){
			return true;
		}
		break;
	case RIGHT:
		if(bean_coo[0] == head_coo[0] && bean_coo[1] < head_coo[1]){
			return true;
		}
		break;
		default:
			//TODO
			break;
	}
	return false;
}

void moveSSS(){							// 吃豆后加一个判断，如果头左方第二格为身体，则行进至不为身体为止
	Coord ago_x = head_coo[0], ago_y = head_coo[1];
	turnToCoord(&ago_x, &ago_y, head_dir);
	if(isWall(ago_x, ago_y)){
		head_dir = getTurnDir(head_dir, RIGHT);
		return;
	}
	if(is_body_ago){
		Coord x = head_coo[0], y = head_coo[1];
		Map left_dir = getTurnDir(head_dir, LEFT);
		turnToCoord(&x, &y, left_dir);
		turnToCoord(&x, &y, left_dir);
		if(!isBody(x, y)){
			is_body_ago = false;
		}
		return;
	}
	if(!go_straight){
		Map wall_dir = getTurnDir(head_dir, LEFT);
		
		if((wall_dir == bean_wall) && okGoeat()){
			head_dir = getTurnDir(bean_wall, DOWN);
			go_straight = true;
			straight_num++;
		} else {
			getNextDir();
		}
	} else if(eat_bean && !is_go_wall) {
		eat_bean_num = straight_num;
		is_go_wall = true;
		
		Coord x = head_coo[0], y = head_coo[1];
		Map left_dir = getTurnDir(head_dir, LEFT);
		for(int i = 0; i < 2; i++){
			turnToCoord(&x, &y, left_dir);
			if(isBody(x, y)){
				is_body_ago = true;
				return;
			}
		}
		
		head_dir = getTurnDir(head_dir, LEFT);
		
	} else if(is_go_wall && straight_num >= 0){
		if(eat_bean_num == straight_num || is_body_turn){
			head_dir = getTurnDir(head_dir, LEFT);
			straight_num--;
			return;
		} 
		if(straight_num == 0){
//			head_dir = getTurnDir(head_dir, RIGHT);
			go_straight = false;
			is_go_wall = false;
			return;
		}
		Coord x = head_coo[0], y = head_coo[1];
		turnToCoord(&x, &y, head_dir);
		if(isBody(x, y)){
			head_dir = getTurnDir(head_dir, RIGHT);
			is_body_turn = true;
		}
		straight_num--;
	} else {
		straight_num++;
	}
}
